from time import sleep
from selenium.common.exceptions import StaleElementReferenceException

from qturboframe.lib.utils.by import By
from qturboframe.lib.utils.CustomError.custom_error import CustomError
from qturboframe.lib.report.log import logger
from qturboframe.lib.webdriver.remote.webdriver import WebDriver
from qturboframe.lib.webdriver.remote.webelement import WebElement
from qturboframe.lib.webdriver.exceptions import SeleniumError
from qturboframe.public_ui.base_element import BaseElement
from qturboframe.public_ui.h_ui.form import Form
from qturboframe.public_ui.h_ui.button import Button
from qturboframe.public_ui.h_ui.table import Table


class MsgBox(BaseElement):
    '''弹出框操作类'''

    def __init__(self, idname=None, father=None, timeout=5):
        if idname:
            super().__init__(idname, father, timeout)
        else:
            if not father:
                message = '未定位元素，father参数不能为None！'
                raise SeleniumError(CustomError.Error_EQ03008001_Parameter_InCorrect, message)
            if isinstance(father, WebDriver):
                self._driver = father
                self.timeout = timeout
            elif isinstance(father, WebElement):
                self._driver = father._parent
                self.timeout = timeout
            else:
                message = 'father参数类型不正确！'
                raise SeleniumError(CustomError.Error_EQ03008001_Parameter_InCorrect, message)
            re_pop_window_class = r'v-transfer-dom'
            re_modal_class = r'h-modal-wrap'
            re_modal_hidden_class = r'h-modal-hidden'
            times = 0
            while times < timeout*5:
                try:
                    # 获取所有有re_pop_window_class属性的div
                    pop_windows = father.find_elements_by_attribute(
                        'css selector', 'div.{}>div.{}'.format(re_pop_window_class, re_modal_class),
                        timeout=0.1)
                    if pop_windows:
                        for pop_window in reversed(pop_windows):
                            class_list = pop_window.get_attribute('class').split(' ')
                            if re_modal_hidden_class not in class_list:
                                self._element = pop_window
                                break
                        else:
                            times = times + 1
                            sleep(1)
                            continue
                        break
                    else:
                        times = times + 1
                        sleep(1)
                        self._element = None
                except StaleElementReferenceException as msg:
                    logger.debug(str(msg))
                    times = times + 1
                    sleep(1)
                    self._element = None
            else:
                self._element = None

    def close(self):
        '''
        弹出框关闭

        :Example:
         - 例: msgbox.close()
        '''
        close_btn = self._element.find_element_by_attribute(
            'css selector', 'div.h-modal-content>a.h-modal-close', timeout=self.timeout)
        close_btn.secure_click()

    def get_pop_window(self):
        '''
        获取弹出框元素

        :Example:
         - 例: msgbox.get_pop_window()
        '''
        try:
            popdiv = self._element.find_element_by_attribute('class name', 'h-modal-content',
                                                            timeout=self.timeout)
            pop_header = popdiv.exist('css selector', 'div.h-modal-header', timeout=self.timeout)
            if pop_header and pop_header.text:
                logger.info('当前操作弹出框：' + pop_header.text)
            else:
                logger.info('打开弹出框。')
            return popdiv
        except Exception as e:
            raise SeleniumError(e)

    def exist(self):
        '''
        判断弹出框是否存在

        :Returns:
            存在返回True，否则返回False

        :Example:
         - 例: msg.exist()
        '''
        if self._element:
            return True
        else:
            return False

    def check(self, ui_expected, checked=False):
        '''
        检查msg_box中文本是否包含ui_expected信息

        :Example:
         - 例: msgbox.check(ui_expected)
        '''
        if not checked:
            return
        try:
            locator = ".h-modal-confirm"
            e = self._element.find_element_by_attribute(By.CSS_SELECTOR, locator, timeout=1)
            actual_text = e.get_attribute("innerText")
        except:
            actual_text = ""
        if ui_expected.strip() in actual_text.strip():
            logger.info("期望值为：{}".format(ui_expected))
            logger.info("实际值为：{}".format(actual_text))
        else:
            message = "期望值为：{}".format(ui_expected)+","+"实际值为：{}".format(actual_text)
            raise SeleniumError(CustomError.Error_EQ03010001_Verify_Expect_Actual_Not_Equal, message)

    def check_header(self, ui_expected):
        '''
        检查msg_box中header中的信息

        :Example:
         - 例: msgbox.check_header(ui_expected)
        '''
        if not self.exist():
            logger.error("当前页面没有弹框")
            raise SeleniumError("当前页面没有弹框")

        try:
            locator = ".h-modal-header"
            e = self._element.find_element_by_attribute(By.CSS_SELECTOR, locator, timeout=1)
            actual_text = e.get_attribute("innerText").strip()
        except:
            actual_text = ""
        if ui_expected.strip() in actual_text.strip():
            logger.info("期望的弹框为：{}".format(ui_expected))
            logger.info("实际的弹框为：{}".format(actual_text))
        else:
            message = "期望的弹框为：{}".format(ui_expected) + "," + "实际的弹框为：{}".format(actual_text)
            raise SeleniumError(CustomError.Error_EQ03010001_Verify_Expect_Actual_Not_Equal, message)

    def check_not_popup_window(self, ui_expected):
        '''
        检查期望的msg_box已经关闭

        :Example:
         - 例: msgbox.check_not_popup_window(ui_expected)
        '''
        #页面没有弹框则说明弹框已经关闭
        if not self.exist():
            logger.info("当前页面没有弹框, {}弹框已经关闭".format(ui_expected))
            return

        #页面有弹框，判断弹框是否为期望要被关闭的弹框，如果是则失败，抛出异常，否则说明期望弹框已经关闭
        try:
            locator = ".h-modal-header"
            e = self._element.find_element_by_attribute(By.CSS_SELECTOR, locator, timeout=1)
            actual_text = e.get_attribute("innerText").strip()
        except:
            actual_text = ""
        if ui_expected.strip() in actual_text.strip():
            message = "{}弹框仍然存在".format(ui_expected)
            raise SeleniumError(CustomError.Error_EQ03014000_Message_Fail_Close, message)
        else:
            logger.info("{}弹框已经关闭".format(ui_expected))

    def not_match(self, ui_error_expected, checked=False):
        '''
        检查msg_box中文本是否不包含ui_expected信息

        :Example:
         - 例: msgbox.check(ui_expected)
        '''
        if not checked:
            return
        try:
            locator = ".h-modal-confirm"
            e = self._element.find_element_by_attribute(By.CSS_SELECTOR, locator, timeout=1)
            actual_text = e.get_attribute("innerText")
        except:
            actual_text = ""
        if ui_error_expected.strip() in actual_text.strip():
            message = "期望值为：{}".format(ui_error_expected) + "," + "实际值为：{}".format(actual_text)
            raise SeleniumError(CustomError.Error_EQ03010002_Verify_Expect_Actual_Equal, message)
            raise SeleniumError("有错误信息")
        else:
            logger.info("期望值为：{}".format(ui_error_expected))
            logger.info("实际值为：{}".format(actual_text))

    def __form(self):
        '''
        获取message box中的form对象
        :Args:
         None

        :Returns:
         None

        :Example:
         - 例1: table = message_box.form()
        '''
        return Form(self._element, timeout=self.timeout)

    def __button(self, button_text):
        '''
        获取消息框中的button对象
        :Args:
         None

        :Returns:
         None

        :Example:
         - 例1: button = message_box.__button()
        '''
        if not self._element:
            message = "没有找到msg box"
            raise SeleniumError(CustomError.Error_EQ03001000_Cannot_Find_Element, message)

        return Button({By.TEXT:button_text},self._element, timeout=self.timeout)

    def auto_fill(self, input_data, button_text=None):
        '''
        填充message box中的form对象
        :Args:
         - input_data:要填充的值
         - button_text: 填充完值后，需要点击的按钮，当为None时，则不点击按钮

        :Returns:
         None

        :Example:
         - 例1: message_box.fill_form(input_data)
        '''
        self.__form().auto_fill(input_data)
        if not button_text:
            self.__button(button_text).js_click()

    def click(self, button_text="确认"):
        '''
        点击消息框中的button
        :Args:
         button_text: button上的文本

        :Returns:
         None

        :Example:
         - 例1: message_box.click_button()
        '''
        if not self._element:
            message = "没有找到msg box"
            raise SeleniumError(CustomError.Error_EQ03001000_Cannot_Find_Element, message)

        return self.__button(button_text).js_click()

    def normal_click(self, button_text="确认"):
        '''
        点击消息框中的button
        :Args:
         button_text: button上的文本

        :Returns:
         None

        :Example:
         - 例1: message_box.click_button()
        '''
        return self.__button(button_text).click()

    def __table(self):
        '''
        获取message box中的table对象
        :Args:
         None

        :Returns:
         None

        :Example:
         - 例1: table = message_box.form()
        '''
        return Table({By.CSS_SELECTOR:".h-table-wrapper"},self._element, timeout=self.timeout)

    def select_row(self, table_dict, turn_page=False):
        '''
        在当前页根据单元格列名和单元格内容勾选行

        :Args:
         - table_dict: 单元格列名和单元格内容，字典类型，例：{列名1:内容1,列名2:内容2}
         - turn_page: 是否自动翻页，默认关闭自动翻页查找功能

        :Example:
         - 例: msg_box.select_row({'姓名':'admin','年龄':'25'}, True)
        '''
        self.__table().select_row(table_dict, turn_page)